/********************************************************
 *
 * FILE NAME:   smartingeegclientagent.h
 *
 * DESCRIPTION:
 *  Module for communication with Smarting EEG Server
 *
 ********************************************************/

#ifndef SMARTINGEEGCLIENTAGENT_H
#define SMARTINGEEGCLIENTAGENT_H

/********************************************************/
/*              Includes                                */
/********************************************************/
#include "signalprocessing/signalprocessing.h"
#include "buffer.h"

#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QBluetoothLocalDevice>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothSocket>

/********************************************************/
/*              Defines                                 */
/********************************************************/
#define SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS 24

/********************************************************/
/*              Macros                                  */
/********************************************************/

/********************************************************/
/*              Typedefs                                */
/********************************************************/
class SmartingEEGClientAgent;
class SmartingEEGClientAgentWorker;

class SmartingEEGClientAgent : public QObject
{
    Q_OBJECT

    friend class SmartingEEGClientAgentWorker;

    Q_PROPERTY(bool bufferOverloaded READ isBufferOverloaded NOTIFY bufferOverloadedChanged)

    /********************************************************/
    /*              Typedefs                                */
    /********************************************************/
    public:
        enum mode_e
        {
            NORMAL_MODE,
            TEST_MODE
        };
        Q_ENUMS(mode_e)

    protected:

    private:
        class SmartingEEGClientAgentOSignal;

        class SmartingEEGClientAgentOSignal : public OSignal
        {
            /********************************************************/
            /*              Typedefs                                */
            /********************************************************/
            public:

            protected:

            private:

            /********************************************************/
            /*              Functions Declarations                  */
            /********************************************************/
            public:
                /********************************************************
                 * Function Name    :   SmartingEEGClientAgentOSignal
                 *
                 * Description      :   Constructor
                 *
                 * Side effects     :
                 *
                 * Comment          :
                 *
                 * Parameters       :
                 *
                 * Returns      	:
                 *
                 * Reviewed by      :   v_duschan@hotmail.com
                 *
                 ********************************************************/
                SmartingEEGClientAgentOSignal(Buffer<sample_t> &buff, size_t &buffUnprocessed, QMutex &buffMtx, QWaitCondition &buffNotEmpty, QWaitCondition &buffNotFull);

                /********************************************************
                 * Function Name    :   onBurstRequest
                 *
                 * Description      :   Called when new burst of samples requested
                 *
                 * Side effects     :
                 *
                 * Comment          :
                 *
                 * Parameters       :   size_t burstLength = burst length
                 *
                 * Returns      	:   true if burst of samples successfully processed, else false
                 *
                 * Reviewed by      :   v_duschan@hotmail.com
                 *
                 ********************************************************/
                bool onBurstRequest(size_t burstLength);

            protected:

            private:

            /********************************************************/
            /*              Variables Declarations                  */
            /********************************************************/
            public:

            protected:

            private:
                Buffer<sample_t> &_buff;
                size_t &_buffUnprocessed;
                QMutex &_buffMtx;
                QWaitCondition &_buffNotEmpty;
                QWaitCondition &_buffNotFull;
        };

    /********************************************************/
    /*              Functions Declarations                  */
    /********************************************************/
    public:
        /********************************************************
         * Function Name    :   SmartingEEGClientAgent
         *
         * Description      :   Constructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   QObject *parent = Qt Object parent of the SmartingEEGClientAgent object
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        explicit SmartingEEGClientAgent(QObject *parent = 0);

        /********************************************************
         * Function Name    :   ~SmartingEEGClientAgent
         *
         * Description      :   Destructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        ~SmartingEEGClientAgent();

        /********************************************************
         * Function Name    :   registerTypes
         *
         * Description      :   Register SmartingEEGClientAgent class to QML
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        static void registerTypes(const char *uri);

        /********************************************************
         * Function Name    :   init
         *
         * Description      :   Initialize SmartingEEGClientAgent
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:   true if initialization succseded, else false
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE bool init();

        /********************************************************
         * Function Name    :   startServerDiscovery
         *
         * Description      :   Start Smarting EEG server discovery
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void startServerDiscovery();

        /********************************************************
         * Function Name    :   stopServerDiscovery
         *
         * Description      :   Stop Smarting EEG server discovery
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void stopServerDiscovery();

        /********************************************************
         * Function Name    :   connectToServer
         *
         * Description      :   Start connecting to Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   const QString &address = MAC address of the server
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void connectToServer(const QString &address);

        /********************************************************
         * Function Name    :   disconnectFromServer
         *
         * Description      :   Start disconnecting from Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void disconnectFromServer();

        /********************************************************
         * Function Name    :   startAcquisition
         *
         * Description      :   Start data acquisition from Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void startAcquisition();

        /********************************************************
         * Function Name    :   stopAcquisition
         *
         * Description      :   Stop data acquisition from Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void stopAcquisition();

        /********************************************************
         * Function Name    :   setMode
         *
         * Description      :   Set working mode of the Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   mode_e mode = working mode
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void setMode(mode_e mode);

        /********************************************************
         * Function Name    :   enableChannel
         *
         * Description      :   Enable acquisition on channel
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   quint8 num = channel number
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void enableChannel(quint8 num);

        /********************************************************
         * Function Name    :   disableChannel
         *
         * Description      :   Disable acquisition on channel
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   quint8 num = channel number
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void disableChannel(quint8 num);

        /********************************************************
         * Function Name    :   enableImpedanceMeasurement
         *
         * Description      :   Enable impedance measurement of Smarting EEG electrodes
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void enableImpedanceMeasurement();

        /********************************************************
         * Function Name    :   disableImpedanceMeasurement
         *
         * Description      :   Disable impedance measurement of Smarting EEG electrodes
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        Q_INVOKABLE void disableImpedanceMeasurement();

        Q_INVOKABLE bool isBufferOverloaded();

        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[0], Channel0OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[1], Channel1OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[2], Channel2OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[3], Channel3OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[4], Channel4OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[5], Channel5OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[6], Channel6OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[7], Channel7OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[8], Channel8OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[9], Channel9OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[10], Channel10OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[11], Channel11OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[12], Channel12OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[13], Channel13OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[14], Channel14OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[15], Channel15OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[16], Channel16OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[17], Channel17OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[18], Channel18OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[19], Channel19OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[20], Channel20OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[21], Channel21OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[22], Channel22OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_channelOSig[23], Channel23OSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_syncOSig, SyncOSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_gyroXOSig, GyroXOSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_gyroYOSig, GyroYOSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_gyroZOSig, GyroZOSignal)
        Q_INVOKABLE EXPORT_SIGNAL(_batteryOSig, BatteryOSignal)

    public slots:

    protected:

    protected slots:

    private:
        void _updateBufferOverloaded();

    private slots:
        /********************************************************
         * Function Name    :   _onDeviceDiscovered
         *
         * Description      :   Emit 'void serverDiscovered(const QString &name, const QString &address)' signal
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   const QBluetoothDeviceInfo &device = bluetooth info of the device
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        void _onDeviceDiscovered(const QBluetoothDeviceInfo &device);

        void _onConnectedToServer();

    signals:
        /********************************************************
         * Function Name    :   serverDiscovered
         *
         * Description      :   Emited when new Smarting EEG server discovered
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   const QString &name = name of the server
         *                      const QString &address = MAC address of the server
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        void serverDiscovered(const QString &name, const QString &address);

        /********************************************************
         * Function Name    :   connectedToServer
         *
         * Description      :   Emited when agent successfully connected to Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        void connectedToServer();

        /********************************************************
         * Function Name    :   disconnectedFromServer
         *
         * Description      :   Emited when agent successfully disconnected from Smarting EEG server
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        void disconnectedFromServer();

        void bufferOverloadedChanged();

    /********************************************************/
    /*              Variables Declarations                  */
    /********************************************************/
    public:

    protected:

    private:
        QThread *_workerThread;
        SmartingEEGClientAgentWorker *_worker;

        QBluetoothLocalDevice *_btDevice;
        QBluetoothDeviceDiscoveryAgent *_btDiscoveryAgent;
        QBluetoothSocket *_btSocket;

        mode_e _mode;
        bool _channelEnabled[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        bool _impedanceMeasurementEnabled;

        Buffer<sample_t> *_channelBuff[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        size_t _channelUnprocessed[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        QMutex *_channelMtx[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        QWaitCondition *_channelNotEmpty[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        QWaitCondition *_channelNotFull[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];
        SmartingEEGClientAgentOSignal *_channelOSig[SMARTINGEEGCLIENTAGENT__NUM_OF_CHANNELS];

        Buffer<sample_t> *_syncBuff;
        size_t _syncUnprocessed;
        QMutex *_syncMtx;
        QWaitCondition *_syncNotEmpty;
        QWaitCondition *_syncNotFull;
        SmartingEEGClientAgentOSignal *_syncOSig;

        Buffer<sample_t> *_gyroXBuff;
        size_t _gyroXUnprocessed;
        QMutex *_gyroXMtx;
        QWaitCondition *_gyroXNotEmpty;
        QWaitCondition *_gyroXNotFull;
        SmartingEEGClientAgentOSignal *_gyroXOSig;

        Buffer<sample_t> *_gyroYBuff;
        size_t _gyroYUnprocessed;
        QMutex *_gyroYMtx;
        QWaitCondition *_gyroYNotEmpty;
        QWaitCondition *_gyroYNotFull;
        SmartingEEGClientAgentOSignal *_gyroYOSig;

        Buffer<sample_t> *_gyroZBuff;
        size_t _gyroZUnprocessed;
        QMutex *_gyroZMtx;
        QWaitCondition *_gyroZNotEmpty;
        QWaitCondition *_gyroZNotFull;
        SmartingEEGClientAgentOSignal *_gyroZOSig;

        Buffer<sample_t> *_batteryBuff;
        size_t _batteryUnprocessed;
        QMutex *_batteryMtx;
        QWaitCondition *_batteryNotEmpty;
        QWaitCondition *_batteryNotFull;
        SmartingEEGClientAgentOSignal *_batteryOSig;

        bool _bufferOverloaded;
};
class SmartingEEGClientAgentWorker : public QObject
{
    Q_OBJECT

    /********************************************************/
    /*              Typedefs                                */
    /********************************************************/
    public:

    protected:

    private:

    /********************************************************/
    /*              Functions Declarations                  */
    /********************************************************/
    public:
        /********************************************************
         * Function Name    :   SmartingEEGClientAgentWorker
         *
         * Description      :   Constructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :   SmartingEEGClientAgent &context = context of the signal
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        explicit SmartingEEGClientAgentWorker(SmartingEEGClientAgent &context);

        /********************************************************
         * Function Name    :   ~SmartingEEGClientAgentWorker
         *
         * Description      :   Destructor
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        ~SmartingEEGClientAgentWorker();

    public slots:

    protected:

    protected slots:

    private:

    private slots:
        /********************************************************
         * Function Name    :   _onReadyRead
         *
         * Description      :   Read and parse data from Bluetooth Socket
         *
         * Side effects     :
         *
         * Comment          :
         *
         * Parameters       :
         *
         * Returns      	:
         *
         * Reviewed by      :   v_duschan@hotmail.com
         *
         ********************************************************/
        void _onReadyRead();

    signals:

    /********************************************************/
    /*              Variables Declarations                  */
    /********************************************************/
    public:

    protected:

    private:
        SmartingEEGClientAgent &_context;

        char *_readBuff;
        qint64 _readUnprocessed;

        Buffer<quint8> *_parseBuff;
        size_t _parseUnprocessed;

};

/********************************************************/
/*              Functions Declarations                  */
/********************************************************/

/********************************************************/
/*              Variables Declarations (IMPORT)         */
/********************************************************/

#endif /* SMARTINGEEGCLIENTAGENT_H */
